
#! /usr/bin/python
# -*- coding: utf-8 -*-

#***********************************
# Data collect
#***********************************

import os
import sys
import time
import threading
import snap7
from queue import *
import struct

import pickle


import app_global
from app_global import *

from db_ctrl import *
from db_conf import *
from plc_helper import *

ONE_DAY_IN_SECONDS = 60 * 60 * 24

log = app_global.gLog

class CDAQPlc(threading.Thread):
    q = Queue(10)
    #model = CFlattenModel() # model calculator
    #synpd = CPlateDataSyn() # plate data syn
    #db = CDBProcessor() #data process: save, select
    #db.connect()

    def __init__(self,kfk_prod=None):
        threading.Thread.__init__(self)
        self.db_dict = {}
        self.client = snap7.client.Client()
        self.client.connect(PLC_ADDR,0,3)
        self.init_plc_db()
        self.kfk_prod = kfk_prod

    def run(self):
        while app_global.SYS_RUN:
            try:
                plc_data = self.read_plc_db()
                if plc_data:
                    if self.kfk_prod:
                        send_data = pickle.dumps(plc_data)
                        self.kfk_prod.send('data_acq', key = b'plc_data', value = send_data)
            except Exception as e:
                log.error("PlateDAQ::run ERR: {}".format(e))
            time.sleep(1)
        self.client.disconnect()

    def init_plc_db(self):
        for data_item in DB_DATA:
            key = "DB_{}".format(data_item[0])
            edx = data_item[3]+data_item[4]

            if key in self.db_dict.keys():
                if self.db_dict[key].edx < edx:
                    self.db_dict[key].edx = edx
            else:
                blk = PLCDBlk(data_item[0],0,edx)
                self.db_dict[key] = blk

    def read_plc_db(self):
        for key in self.db_dict:
            data = self.client.db_read(self.db_dict[key].idx, self.db_dict[key].stx,self.db_dict[key].edx)
            self.db_dict[key].datablk = data
        
        ins_data = {}

        for item in DB_DATA:
            
            key = "DB_{}".format(item[0])
            if item[2]=="float":
                _val, = struct.iter_unpack(">f",self.db_dict[key].datablk[item[4]:item[3]+item[4]])#DB_HEAD[item[0]][item[4]:item[3]+item[4]])
                val = round(_val[0],4)
            elif item[2] == "double":
                _val, = struct.iter_unpack(">d",self.db_dict[key].datablk[item[4]:item[3]+item[4]])#DB_HEAD[item[0]][item[4]:item[3]+item[4]])
                val = round(_val[0],4)
            elif item[2]=="int":
                _val, = struct.iter_unpack(">i",self.db_dict[key].datablk[item[4]:item[3]+item[4]])#DB_HEAD[item[0]][item[4]:item[3]+item[4]])
                val = _val[0]
            elif item[2]=="uint":
                _val, = struct.iter_unpack(">I",self.db_dict[key].datablk[item[4]:item[3]+item[4]])#DB_HEAD[item[0]][item[4]:item[3]+item[4]])
                val = _val[0]
            elif item[2]=="short" or item[2]=="word":#2bits
                _val, = struct.iter_unpack(">h",self.db_dict[key].datablk[item[4]:item[3]+item[4]])#DB_HEAD[item[0]][item[4]:item[3]+item[4]])
                val = _val[0]
            elif item[2]=="char":
                _val, = struct.iter_unpack(">b",self.db_dict[key].datablk[item[4]:item[3]+item[4]])#DB_HEAD[item[0]][item[4]:item[3]+item[4]])
                val = _val[0]
            elif item[2]=="bool":
                _val, = struct.iter_unpack(">b",self.db_dict[key].datablk[item[4]:item[3]+item[4]])
                val = (_val[0]>>item[5])&0x01
                
            elif item[2]=="string":
                str1 = self.db_dict[key].datablk[item[4]:item[3]+item[4]]#DB_HEAD[item[0]][item[4]:item[3]+item[4]]
                val = str1.decode(encoding='utf-8')
                val = val.strip()

            ins_data[item[1]] = val
        
        return ins_data


if __name__=="__main__":
    from kafka import *
    log.info("sys start")
    producer = KafkaProducer(bootstrap_servers=['0.0.0.0:9092'])
    
    daq = CDAQPlc(producer);
    daq.start()    

    try:
        while True:
            time.sleep(ONE_DAY_IN_SECONDS)
    except KeyboardInterrupt:
        app_global.SYS_RUN = False

    daq.join()

    producer.close()
